﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using EnvDTE;
using System.Reflection;
using VSLangProj;
using System.IO;
using Sharp.AssemblyUtilities;

namespace Sharp.UnusedReferences
{
	static class Extensions
	{
		//public static Assembly GetAssembly(this Project ProjectInstance, Configuration ConfigurationInstance)
		//{
		//    string stringAssemblyPath = ProjectInstance.GetAssemblyPath(ConfigurationInstance);
		//    if(string.IsNullOrEmpty(stringAssemblyPath) || !File.Exists(stringAssemblyPath))
		//    {
		//        return null;
		//    }
		//    try
		//    {
		//        Assembly result = Assembly.ReflectionOnlyLoadFrom(stringAssemblyPath);

		//        return result;

		//        //return Assembly.ReflectionOnlyLoadFrom(stringAssemblyPath);
		//        //return Assembly.LoadFrom(stringAssemblyPath);
		//    }
		//    catch(Exception ExceptionLoadingAssembly)
		//    {
		//        //Refer to the documentation of "Assembly ..::.Load Method ( array<Byte []()>[])"
		//        //at "http://127.0.0.1:47873/help/1-11516/ms.help?method=page&id=M%3ASYSTEM.REFLECTION.ASSEMBLY.LOAD(SYSTEM.BYTE%5B%5D)&product=VS&productVersion=100&topicVersion=100&locale=EN-US&topicLocale=EN-US"
		//        //and at "http://msdn.microsoft.com/en-us/library/w368ysh2(v=VS.100).aspx"
		//        return null;
		//    }
		//}
		public static string GetAssemblyPath(this Project ProjectInstance, Configuration ConfigurationInstance)
		{
			if(ConfigurationInstance is ProjectConfigurationProperties)
			{
				return ((ProjectConfigurationProperties)ConfigurationInstance).OutputPath;
			}
			Property PropertyOutputPath = ConfigurationInstance.Properties.ItemByName("OutputPath");
			if(PropertyOutputPath == null)
			{
				return string.Empty;
			}
			string stringOutputFileName = ProjectInstance.GetOutputFileName(ConfigurationInstance);
			if(string.IsNullOrEmpty(stringOutputFileName))
			{
				return string.Empty;
			}
			string stringOutputPath = Convert.ToString(PropertyOutputPath.Value);
			/*
			The output folder can have these patterns:
				1) "drive:\folder"
				2) "\\server\folder"
				3) "..\..\folder"
				4) "folder"
			*/
			if(Path.IsPathRooted(stringOutputPath))
			{
				//This is the case 1: "drive:\folder"
				return Path.Combine(stringOutputPath, stringOutputFileName);
			}
			else if(stringOutputPath.StartsWith(Path.DirectorySeparatorChar.ToString() + Path.DirectorySeparatorChar.ToString()))
			{
				//This is the case 2: "\\server\folder"
				return Path.Combine(stringOutputPath, stringOutputFileName);
			}
			//else if(stringOutputPath.Length >= 2 && stringOutputPath[1] == Path.VolumeSeparatorChar)
			//{
			//    //This is the case 1: "drive:\folder"
			//    return Path.Combine(stringOutputPath, stringOutputFileName);
			//}
			else if(stringOutputPath.IndexOf("..\\") != -1)
			{
				//This is the case 3: "..\..\folder"
				return Path.Combine(Helper.ConvertToAbsolute(ProjectInstance.FullName, stringOutputPath), stringOutputFileName);
			}
			else
			{
				return string.Format("{0}\\{1}{2}", Path.GetDirectoryName(ProjectInstance.FullName), PropertyOutputPath.Value, stringOutputFileName);
			}
		}
		public static Property ItemByName(this Properties PropertiesInstance, string Name)
		{
			foreach(Property PropertyInstance in PropertiesInstance)
			{
				if(PropertyInstance.Name == Name)
				{
					return PropertyInstance;
				}
			}
			return null;
		}
		public static string GetOutputFileName(this Project ProjectInstance, Configuration ConfigurationInstance)
		{
			Property PropertyOutputFileName = ProjectInstance.Properties.ItemByName("OutputFileName");
			if(PropertyOutputFileName == null)
			{
				Property PropertyItemName = ProjectInstance.Properties.ItemByName("ItemName");
				if(PropertyItemName == null)
				{
					return string.Empty;
				}
				Property PropertyConfigurationType = ConfigurationInstance.Properties.ItemByName("ConfigurationType");
				if(PropertyConfigurationType == null)
				{
					return string.Empty;
				}
				switch(Convert.ToInt16(PropertyConfigurationType.Value))
				{
					case 1:
					return string.Format("{0}.exe", PropertyItemName.Value);
					case 2:
					return string.Format("{0}.dll", PropertyItemName.Value);
					case 4:
					return string.Format("{0}.lib", PropertyItemName.Value);
					default:
					return string.Empty;
				}
			}
			return Convert.ToString(PropertyOutputFileName.Value);
		}
		public static AssemblyName[] GetReferencedAssemblies(this Project ProjectInstance, Configuration ConfigurationInstance, AssemblyName[] ScanExcludedAssemblies)
		{
			string stringAssemblyPath = ProjectInstance.GetAssemblyPath(ConfigurationInstance);
			AssemblyName[] Result;

			using(AssemblyIsolatedLoader AssemblyScannerInstance = new AssemblyIsolatedLoader(stringAssemblyPath, false, false, true, ScanExcludedAssemblies))
			{
				Result = AssemblyScannerInstance.UsedAssemblies;
			}
			return Result;
		}
		public static AssemblyName[] GetReferencedAssemblies(this Project ProjectInstance, AssemblyName[] ScanExcludedAssemblies)
		{
			List<AssemblyName> Result = new List<AssemblyName>();
			foreach(Configuration ConfigurationInstance in ProjectInstance.ConfigurationManager)
			{
				foreach(AssemblyName AssemblyNameUsed in ProjectInstance.GetReferencedAssemblies(ConfigurationInstance, ScanExcludedAssemblies))
				{
					if(!Result.Contains(AssemblyNameUsed))
					{
						Result.Add(AssemblyNameUsed);
					}
				}
			}
			return Result.ToArray();
		}
		public static string[] GetReferencedAssembliesAsStrings(this Project ProjectInstance, Configuration ConfigurationInstance, AssemblyName[] ScanExcludedAssemblies)
		{
			List<string> Result = new List<string>();
			foreach(AssemblyName AN in ProjectInstance.GetReferencedAssemblies(ConfigurationInstance, ScanExcludedAssemblies))
			{
				Result.Add(AN.Name);
			}
			return Result.ToArray();
		}
		public static string[] GetReferencedAssembliesAsStrings(this Project ProjectInstance, AssemblyName[] ScanExcludedAssemblies)
		{
			List<string> Result = new List<string>();
			foreach(Configuration ConfigurationInstance in ProjectInstance.ConfigurationManager)
			{
				foreach(string AssemblyNameUsed in ProjectInstance.GetReferencedAssembliesAsStrings(ConfigurationInstance, ScanExcludedAssemblies))
				{
					if(!Result.Contains(AssemblyNameUsed))
					{
						Result.Add(AssemblyNameUsed);
					}
				}
			}
			return Result.ToArray();
		}
		public static bool ContainsEx(this List<AssemblyName> list, AssemblyName Name)
		{
			foreach(AssemblyName AssemblyNameInstance in list)
			{
				if(AssemblyNameInstance.FullName == Name.FullName)
				{
					return true;
				}
			}
			return false;
		}
		public static bool ContainsEx(this List<AssemblyName> list, IVsHierarchyWrapper Rf)
		{
			foreach(AssemblyName AssemblyNameInstance in list)
			{
				if(AssemblyNameInstance.Name.ToLower() == Rf.Name.ToLower())
				{
					return true;
				}
			}
			return false;
		}
		public static bool ContainsEx(this List<string> list, IVsHierarchyWrapper Rf)
		{
			foreach(string AssemblyNameInstance in list)
			{
				if(AssemblyNameInstance == Rf.Name)
				{
					return true;
				}
			}
			return false;
		}
		public static void AddRangeEx(this List<AssemblyName> list, IEnumerable<AssemblyName> collection)
		{
			foreach(AssemblyName AssemblyNameInstance in collection)
			{
				if(!list.ContainsEx(AssemblyNameInstance))
				{
					list.Add(AssemblyNameInstance);
				}
			}
		}
		public static void AddRangeEx(this List<string> list, IEnumerable<string> collection)
		{
			foreach(string AssemblyNameInstance in collection)
			{
				if(!list.Contains(AssemblyNameInstance))
				{
					list.Add(AssemblyNameInstance);
				}
			}
		}
		public static string GetTypeName(this Reference ReferenceInstance)
		{
			if(ReferenceInstance.Type == prjReferenceType.prjReferenceTypeActiveX)
			{
				return "COM";
			}
			else
			{
				return "Assembly";
			}
		}
		public static List<CheckBoxTreeViewItem> GetCheckBoxItems(this System.Windows.Controls.TreeView TreeViewInstance)
		{
			List<CheckBoxTreeViewItem> Result = new List<CheckBoxTreeViewItem>();
			foreach(object objectItem in TreeViewInstance.Items)
			{
				Result.Add((CheckBoxTreeViewItem)objectItem);
			}
			return Result;
		}
		public static IVsHierarchyWrapper GetIVsHierarchyWrapper(this CheckBoxTreeViewItem CheckBoxTreeViewItemInstance)
		{
			return (IVsHierarchyWrapper)CheckBoxTreeViewItemInstance.Tag;
		}
	}
}
